import { MIME_TYPE } from 'configs/contentPage';
import { ILocalStore } from 'hooks/useLocalStore';
import { Base64 } from 'js-base64';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { FileContentApi, FileContentModel, normalizeFileContent } from 'store/models';
import RootStore from 'store/RootStore';
import ApiStore, { FetchMeta } from 'store/RootStore/ApiStore';

type PrivateFields = '_fileContent' | '_fileContentMeta' | '_isDocFile' | '_docExtension' | '_isSupported';

export default class ContentStore implements ILocalStore {
    private readonly _ApiStore = new ApiStore();
    private _fileContent?: FileContentModel;
    private _fileContentMeta: FetchMeta = FetchMeta.INITIAL;
    private _isDocFile: boolean = true;
    private _docExtension = '';
    private _isSupported: boolean = true;
    private readonly _fetchMetaReaction: IReactionDisposer;

    constructor() {
        makeObservable<ContentStore, PrivateFields>(this, {
            _fileContent: observable,
            _fileContentMeta: observable,
            _isDocFile: observable,
            _docExtension: observable,
            _isSupported: observable,
            isDocFile: computed,
            isSupported: computed,
            fileContent: computed,
            fetchFileContent: action.bound,
        });

        this.fetchFileContent();

        this._fetchMetaReaction = reaction(
            () => this._fetchRequestsMeta,
            (meta) => {
                RootStore.pageLoader.getFetchRequestsMeta(meta);
            },
        );
    }

    get _fetchRequestsMeta(): FetchMeta[] {
        return [this._fileContentMeta];
    }
    get fileContent(): FileContentModel | undefined {
        return this._fileContent;
    }
    get isDocFile(): boolean {
        return this._isDocFile;
    }
    get isSupported(): boolean {
        return this._isSupported;
    }
    get docExtension(): string {
        return this._docExtension;
    }

    fetchFileContent = async (): Promise<void> => {
        this._fileContentMeta = FetchMeta.FETCHING;
        try {
            const result = await this._ApiStore.getApiRequest<FileContentApi>(`/repos${window.location.pathname}`, {
                params: {
                    ref: RootStore.locationStore.getSearchParams('ref'),
                },
            });

            runInAction(() => {
                this._fileContent = normalizeFileContent({
                    ...result.data,
                    content: Base64.decode(result.data.content),
                });
                this._docExtension = result.data.path.match(/\.([^.]+)$/)?.[1] ?? '';
                this._isDocFile = Object.keys(MIME_TYPE).includes(this._docExtension);
                this._isSupported = this._isDocFile || !!this._fileContent.content.length;
                this._fileContentMeta = FetchMeta.FETCHED;
            });
        } catch {
            runInAction(() => {
                this._fileContent = undefined;
                this._fileContentMeta = FetchMeta.ERROR;
            });
        }
    };

    destroy(): void {
        this._fetchMetaReaction();
    }
}
